---
title: Integration Testing
description: Utilities for testing Apollo Server
---

Apollo Server uses a [multi-step request pipeline](../integrations/plugins/#request-lifecycle-event-flow) to validate and execute incoming GraphQL operations. This pipeline supports integration with custom plugins at each step, which can affect an operation's execution. Because of this, it's important to perform **integration tests** with a variety of operations to ensure your request pipeline works as expected.

There are two main options for integration testing with Apollo Server:

- Using `ApolloServer`'s `executeOperation` method.
- Setting up an HTTP client to query your server.

## Testing using `executeOperation`

Apollo Server's `executeOperation` method enables you to run operations through the request pipeline _without_ sending an HTTP request.

The [`executeOperation` method](../api/apollo-server#executeoperation) accepts the following arguments:

- An object that describes the GraphQL operation to execute.
  - This object must include a `query` field specifying the GraphQL operation to run. You can use `executeOperation` to execute both queries and mutations, but both use the `query` field.
- An optional second object that is used as the operation's [`contextValue`](../data/context/#the-contextvalue-object)).

Below is a simplified example of setting up a test using the JavaScript testing library [Jest](https://jestjs.io/):

<MultiCodeBlock>

```ts title="index.test.ts"
// For clarity in this example we included our typeDefs and resolvers above our test,
// but in a real world situation you'd be importing these in from different files
const typeDefs = `#graphql
  type Query {
    hello(name: String): String!
  }
`;

const resolvers = {
  Query: {
    hello: (_, { name }) => `Hello ${name}!`,
  },
};

it('returns hello with the provided name', async () => {
  const testServer = new ApolloServer({
    typeDefs,
    resolvers,
  });

  const response = await testServer.executeOperation({
    query: 'query SayHelloWorld($name: String) { hello(name: $name) }',
    variables: { name: 'world' },
  });

  // Note the use of Node's assert rather than Jest's expect; if using
  // TypeScript, `assert`` will appropriately narrow the type of `body`
  // and `expect` will not.
  assert(response.body.kind === 'single');
  expect(response.body.singleResult.errors).toBeUndefined();
  expect(response.body.singleResult.data?.hello).toBe('Hello world!');
});
```

</MultiCodeBlock>

Note that when testing, any errors in parsing, validating, and executing your GraphQL operation are returned in the nested `errors` field of the result. As with any GraphQL response, these errors are not _thrown_.

You don't need to start your server before calling `executeOperation`. The server instance will start automatically and throw any startup errors.

To expand on the example above, here's a full integration test being run against a test instance of `ApolloServer`. This test imports all of the important pieces to test (`typeDefs`, `resolvers`, `dataSources`) and creates a new instance of `ApolloServer`.

```ts title="integration.test.ts"
it('fetches single launch', async () => {
  const userAPI = new UserAPI({ store });
  const launchAPI = new LaunchAPI();

  // highlight-start
  // ensure our server's context is typed correctly
  interface ContextValue {
    user: User;
    dataSources: {
      userAPI: UserAPI;
      launchAPI: LaunchAPI;
    };
  }
  // highlight-end

  // create a test server to test against, using our production typeDefs,
  // resolvers, and dataSources.
  const server = new ApolloServer<ContextValue>({
    typeDefs,
    resolvers,
  });

  // mock the dataSource's underlying fetch methods
  launchAPI.get = jest.fn(() => [mockLaunchResponse]);
  userAPI.store = mockStore;
  userAPI.store.trips.findAll.mockReturnValueOnce([
    { dataValues: { launchId: 1 } },
  ]);

  // run the query against the server and snapshot the output
  const res = await server.executeOperation(
    {
      query: GET_LAUNCH,
      variables: { id: 1 },
    },
    {
      // highlight-start
      contextValue: {
        user: { id: 1, email: 'a@a.a' },
        dataSources: {
          userAPI,
          launchAPI,
        },
      },
      // highlight-end
    },
  );

  expect(res).toMatchSnapshot();
});
```

The example above includes a test-specific [context value](../data/context/#the-contextvalue-object), which provides data directly to the `ApolloServer` instance, bypassing any `context` initialization function you have.

If you want to test the behavior of your `context` function directly, we recommend running actual HTTP requests against your server.

> For examples of both integration and end-to-end testing we recommend checking out the [tests included in the Apollo fullstack tutorial](https://github.com/apollographql/fullstack-tutorial/tree/master/final/server/src/__tests__).

## End-to-end testing

Instead of bypassing the HTTP layer, you might want to fully run your server and test it with a real HTTP client. Apollo Server doesn't provide built-in support for this at this time.

Instead, you can run operations against your server using a combination of any HTTP or GraphQL client such as [`supertest`](https://www.npmjs.com/package/supertest) or [Apollo Client's HTTP Link](/react/api/link/apollo-link-http/).

Below is an example of writing an end-to-end test using the `@apollo/server` and `supertest` packages:

<MultiCodeBlock>

```ts title="server.test.ts"
// we import a function that we wrote to create a new instance of Apollo Server
import { createApolloServer } from '../server';

// we'll use supertest to test our server
import request from 'supertest';

// this is the query for our test
const queryData = {
  query: `query sayHello($name: String) {
    hello(name: $name)
  }`,
  variables: { name: 'world' },
};

describe('e2e demo', () => {
  let server, url;

  // before the tests we spin up a new Apollo Server
  beforeAll(async () => {
    // Note we must wrap our object destructuring in parentheses because we already declared these variables
    // We pass in the port as 0 to let the server pick its own ephemeral port for testing
    ({ server, url } = await createApolloServer({ port: 0 }));
  });

  // after the tests we'll stop the server
  afterAll(async () => {
    await server?.stop();
  });

  it('says hello', async () => {
    // send our request to the url of the test server
    const response = await request(url).post('/').send(queryData);
    expect(response.errors).toBeUndefined();
    expect(response.body.data?.hello).toBe('Hello world!');
  });
});
```

</MultiCodeBlock>

You can also view and fork this complete example on CodeSandbox:

<ButtonLink
  href="https://codesandbox.io/s/github/apollographql/docs-examples/tree/main/apollo-server/v5/integration-testing?fontsize=14&hidenavigation=1&theme=dark"
  size="lg"
>
  Edit in CodeSandbox
</ButtonLink>
